package cn.jly.spring.annotation.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author lanyangji
 * @description 日志切面
 * @date 2020/11/14 上午 10:12
 */
@Slf4j
@Component
@Aspect
@Order(1)
public class LoggerAspect {

    @Pointcut("execution(* cn.jly.spring.annotation.aop.service.MathCalculatorService.*(..))")
    public void expressionStr() {
    }

    /**
     * 前置通知
     *
     * @param joinPoint
     */
    @Before("expressionStr()")
    public void before(JoinPoint joinPoint) {
        final Object[] args = joinPoint.getArgs();
        log.info("方法入参为 --> " + Arrays.toString(args));

        final String methodName = joinPoint.getSignature().getName();
        log.info("方法名为 --> " + methodName);

        final String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        log.info("所在类名为 --> " + declaringTypeName);
    }

    /**
     * 返回通知
     *
     * @param result
     */
    @AfterReturning(value = "expressionStr()", returning = "result")
    public void afterReturn(JoinPoint joinPoint, Object result) {
        log.info("返回结果为 --> " + result);
    }

    /**
     * 异常通知
     *
     * @param ex
     */
    @AfterThrowing(value = "expressionStr()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        log.error("方法产生的异常原因为 --> " + ex.getMessage());
    }

    /**
     * 最终通知
     */
    @After(value = "expressionStr()")
    public void after() {
        log.info("最终通知 ..");
    }

    @Around("expressionStr()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object res = null;
        try {
            // 前置通知
            log.info(" 环绕通知(前置通知) ---------> 方法入参 --> " + Arrays.toString(proceedingJoinPoint.getArgs()));

            // 执行目标方法
            res = proceedingJoinPoint.proceed();

            // 返回通知
            log.info(" 环绕通知（返回通知） ---------> 方法返回值 --> " + res);

        } catch (Throwable throwable) {
            log.error(" 环绕通知（异常通知） ---------> 异常信息为 --> " + throwable.getMessage());
        } finally {
            // 最终通知
            log.info(" 环绕通知 ---------> 最终通知");
        }

        return res;
    }
}
